<?php

namespace randy\tools\units;

use think\db\exception\DbException;
use think\db\Query;
use think\Paginator;

class MyQuery extends Query
{
    /**
     * 设置Like查询条件
     *
     * @param string|array $fields 查询字段
     * @param string       $input  输入类型 get|post
     * @param string       $alias  别名分割符
     *
     * @return MyQuery
     */
    public function like($fields, $input = 'params', $alias = '#')
    {
        $data = is_array($input) ? $input : input();
        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }
            if (isset($data[$dk]) && $data[$dk] !== '') {
                if ($qk) {
                    $this->where("{$qk}.{$dk}", 'LIKE', "%{$data[$dk]}%");
                } else {
                    $this->where($dk, 'LIKE', "%{$data[$dk]}%");
                }
            }
        }

        return $this;
    }

    public function keyWrod($fields, $input = 'param')
    {
        $data = is_array($input) ? $input : input();
        if (isset($data['keyword'])) {
            $this->whereLike($fields, sprintf('%%%s%%', $data['keyword']));
        }

        return $this;
    }

    public function whereNotDelete() : MyQuery
    {
        $this->where('is_delete', 0);
        return $this;
    }


    /**
     * 设置Equal查询条件
     *
     * @param string|array $fields 查询字段
     * @param string|array $input  输入类型 get|post
     * @param string       $alias  别名分割符
     *
     * @return $this
     */
    public function equal($fields, $input = 'param', $alias = '#')
    {
        $data = is_array($input) ? $input : input();

        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }
            if (isset($data[$dk]) && $data[$dk] !== '') {
                if ($qk) {
                    $this->where($qk . '.' . $dk, '=', "{$data[$dk]}");
                } else {
                    $this->where($dk, '=', "{$data[$dk]}");
                }
            }
        }
        return $this;
    }

    public function findInSet($fields, $input = 'param', $alias = '#')
    {
        $data = is_array($input) ? $input : input();
        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }
            if (isset($data[$dk]) && $data[$dk] !== '') {
                $value = $data[$dk];
                if ($qk) {
                    $this->whereRaw("FIND_IN_SET( '{$value}' ,$qk.$dk )");
                } else {
                    $this->whereRaw("FIND_IN_SET( '{$value}' , $dk )");
                }
            }
        }

        return $this;
    }

    public function findOrNew($id, $columns = ['*'])
    {
        if (
            !is_null(
                $model = $this->field($columns)
                              ->find($id))) {
            return $model;
        }
        return new $this();
    }

    /**
     * 设置Equal查询条件
     *
     * @param string|array $fields 查询字段
     * @param string|array $input  输入类型 get|post
     * @param string       $alias  别名分割符
     *
     * @return $this
     */
    public function lt($fields, $input = 'param', $alias = '#')
    {
        $data = is_array($input) ? $input : input();

        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }

            if (isset($data[$dk]) && $data[$dk] !== '') {
                if ($qk) {
                    $this->where($dk . '.' . $dk, '<', "{$data[$dk]}");
                } else {
                    $this->where($dk, '<', "{$data[$dk]}");
                }
            }
        }

        return $this;
    }


    /**
     * 设置Equal查询条件
     *
     * @param string|array $fields 查询字段
     * @param string|array $input  输入类型 get|post
     * @param string       $alias  别名分割符
     *
     * @return $this
     */
    public function gt($fields, $input = 'param', $alias = '#')
    {
        $data = is_array($input) ? $input : input();

        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }

            if (isset($data[$dk]) && $data[$dk] !== '') {
                if ($qk) {
                    $this->where($dk . '.' . $dk, '>', "{$data[$dk]}");
                } else {
                    $this->where($dk, '>', "{$data[$dk]}");
                }
            }
        }
        return $this;
    }


    /**
     * 设置IN区间查询
     *
     * @param string $fields 查询字段
     * @param string $split  输入分隔符
     * @param string $input  输入类型 get|post
     * @param string $alias  别名分割符
     *
     * @return $this
     */
    public function in(string $fields, array $data = [], string $alias = '#')
    {
        $data = $data ?: input();
        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }
            if (isset($data[$dk]) && $data[$dk] !== []) {
                if ($qk) {
                    $this->where($qk . '.' . $dk, 'IN', $data[$dk]);
                } else {
                    $this->where($dk, 'IN', $data[$dk]);
                }
            }
        }
        return $this;
    }

    /**
     * 设置内容区间查询
     *
     * @param string|array $fields 查询字段
     * @param string       $split  输入分隔符
     * @param string       $input  输入类型 get|post
     * @param string       $alias  别名分割符
     *
     * @return $this
     */
    public function valueBetween($fields, $split = ' - ', $input = 'param', $alias = '#')
    {
        return $this->setBetweenWhere($fields, $split, $input, $alias);
    }

    /**
     * 设置区域查询条件
     *
     * @param string|array $fields 查询字段
     * @param string       $input  输入类型
     * @param string       $alias  别名分割符
     * @param null         $callback
     *
     * @return $this
     */
    private function setBetweenWhere($fields, $input = 'null', $alias = ' - ', $callback = null)
    {
        $data = is_array($input) ? $input : input();

        foreach (is_array($fields) ? $fields : explode(',', $fields) as $field) {
            [
                $dk,
                $qk
            ] = [
                $field,
                ''
            ];
            if (stripos($field, $alias) !== false) {
                [
                    $dk,
                    $qk
                ] = explode($alias, $field);
            }
            if (isset($data[$dk]) && $data[$dk]) {
                if (is_array($data[$dk])) {
                    [
                        $begin,
                        $after
                    ] = $data[$dk];
                } else {
                    [
                        $begin,
                        $after
                    ] = explode(' - ', $data[$dk]);
                }

                if (is_callable($callback)) {
                    $after = call_user_func($callback, $after, 'after');
                    $begin = call_user_func($callback, $begin, 'begin');
                }

                $this->where($qk ? $qk . '.' . $dk : $dk, 'between', [
                    $begin,
                    $after
                ]);
            }
        }
        return $this;
    }

    /**
     * 设置日期时间区间查询
     *
     * @param string|array $fields 查询字段
     * @param string       $split  输入分隔符
     * @param string       $input  输入类型
     * @param string       $alias  别名分割符
     *
     * @return $this
     */
    public function dateBetween($fields, $input = [], $alias = '#')
    {
        $input = $input ?: input();
        return $this->setBetweenWhere($fields, $input, $alias, function ($value, $type)
        {
            if ($type === 'after') {
                return "{$value} 23:59:59";
            } else {
                return "{$value} 00:00:00";
            }
        });
    }

    /**
     * 设置时间戳区间查询
     *
     * @param string|array $fields 查询字段
     * @param string       $split  输入分隔符
     * @param string       $input  输入类型
     * @param string       $alias  别名分割符
     *
     * @return $this
     */
    public function timeBetween($fields, $split = ' - ', $input = 'param', $alias = '#')
    {
        return $this->setBetweenWhere($fields, $split, $input, $alias, function ($value, $type)
        {
            if ($type === 'after') {
                return strtotime("{$value} 23:59:59");
            } else {
                return strtotime("{$value} 00:00:00");
            }
        });
    }

    public function setOrder($fields, $split = ',')
    {
        $order = explode($split, $fields);
        foreach ($order as $v) {
            $this->order($v);
        }
        return $this;
    }

    public function setLimit($limit)
    {
        $this->limit($limit);
        return $this;
    }

    /**
     * 设置读取字段
     *
     * @param mixed ...$args
     *
     * @return $this
     *
     *
     * @author : Randy_chen
     * @Date   : 2019/7/5
     * @Time   : 21:08
     */
    public function fields(...$args) : MyQuery
    {
        $this->field($args);
        return $this;
    }

    public function orderByDesc($column) : MyQuery
    {
        return $this->orderBy($column, 'desc');
    }

    public function orderBy($column, $direction = 'asc') : MyQuery
    {
        return $this->order($column, $direction);
    }

    public function latest($column = 'create_time')
    {
        return $this->orderBy($column, 'desc');
    }

    public function oldest($column = 'create_time') : MyQuery
    {
        return $this->orderBy($column, 'asc');
    }

    /**
     * 分页查询
     *
     * @access public
     *
     * @param int|bool $simple 是否简洁模式或者总记录数
     * @param array    $config
     *
     * @return Paginator
     * @throws DbException
     */
    public function _paginate($simple = false, array $config = []) : \think\Paginator
    {
        return parent::paginate([
            'list_rows' => request()->param('page_size', 25),
            'page'      => request()->param('page_index', 1)
        ], $simple, $config);
    }

    /**
     * @throws \think\db\exception\ModelNotFoundException
     * @throws DbException
     * @throws \think\db\exception\DataNotFoundException
     */
    public function _page()
    {
        $page = request()->param('page_index', 1);
        $page_size = request()->param('page_size', 25);
        $offset = $page - 1;
        return $this->limit($offset * $page_size, $page_size)
                    ->select();
    }

    public function range($key = 'store_id')
    {
        if (get_stores() === 'ALL') {
            return $this;
        }
        $this->whereIn($key, get_stores());
        return $this;
    }

    public function search_delete($flag = 0, $field = 'is_delete')
    {
        $this->where($field, $flag);
        return $this;
    }
}